Studies preview data Provider
Provider is designed to calculate indicator data on the preview screen and transfer the calculated data to the library. The indicator is calculated as a single instance.
/*** Interface for receiving calculated study data for studies preview screen** When calculating data for a preview quote, parameters selected by user are transferred to this interface, then the calculated study is received from here** When connecting dxCharts library, developer can implement this interface or use the default implementation [com.devexperts.dxcharts.provider.studies.DxStudiesPreviewDataProviderImplementation] and pass it to the library using [DxChartsDataProviders] data class** The [dataFlow] property is used to get calculated study data. It is a StateFlow that emits a [StudiesData] object representing the study data.** The [setPreviewCandles] method is used to set candles data for study calculation.** The [setPreviewStudySetting] method is used to set study configuration that has to be calculated.** The [updateTradingSessions] method is used to update trading sessions for study.*/interface DxChartsStudiesPreviewDataProvider {/*** Flow of receiving calculated study data** This property is a StateFlow that emits a [StudiesData] object. The [StudiesData] object represents the calculated study data for a particular study.*/val dataFlow: StateFlow<StudiesData?>/*** Sets candles data for study calculation** This method is used to set the candles data that will be used for calculating the study. The candles data is represented by a [DxChartsCandles] object.** @param candles The candles data.*/fun setPreviewCandles(candles: DxChartsCandles)/*** Sets study configuration that has to be calculated** This method is used to set the study configuration that will be calculated. The configuration is represented by a [StudiesSetting] object.** @param studySetting The study configuration.*/fun setPreviewStudySetting(studySetting: StudiesSetting)/*** Updates trading sessions for study calculators** This method is used to update the trading sessions that will be used for calculating the study. Each trading session is represented by a [TradingSession] object.** @param sessions The list of trading sessions.*/fun updateTradingSessions(sessions: List<TradingSession>)}
Methods of the interface:
setPreviewCandles
- sets candles data for the indicator that should be calculated.setPreviewStudySetting
- sets the indicator settings for calculation.updateTradingSessions
- sets trading sessions data for indicator calculation.
Data is sent by updating the state of the dataFlow
variable. It is represented as com.devexperts.dxcharts.provider.StudiesData
object.
Incoming data is represented as com.devexperts.dxcharts.provider.StudiesSetting
object.
The preview of the indicator:

Here is the default implementation of DxChartsStudiesPreviewDataProvider
:
/*** Implementation of the DxChartsStudiesPreviewDataProvider interface, providing functionality* to manage preview studies data and candles for DX charts.** @property _dataFlow Internal mutable state flow to emit preview studies data to the UI.* @property dataFlow Exposed immutable state flow to observe preview studies data from the UI.* @property previewCandlesState Internal mutable state flow to manage preview DX chart candles.* @property previewStudyState Internal mutable state flow to manage the preview studies setting.* @property sessionsFlow Internal mutable state flow to manage trading sessions for preview.* @property previewExecutorService Executor service for managing background tasks specific to previews.* @property previewJob Background job for executing preview data processing.* @property _errorFlow Internal [MutableStateFlow] for sending errors.* @property errorFlow [StateFlow] for sending errors.*/class DxStudiesPreviewDataProviderImplementation : DxChartsStudiesPreviewDataProvider,DxChartsErrorProvider<StudiesPreviewProviderError> {private val _dataFlow: MutableStateFlow<StudiesData?> =MutableStateFlow(null)private val previewCandlesState: MutableStateFlow<DxChartsCandles> =MutableStateFlow(DxChartsCandles())private val previewStudyState: MutableStateFlow<StudiesSetting?> =MutableStateFlow(null)private val sessionsFlow: MutableStateFlow<List<TradingSession>> = MutableStateFlow(emptyList())private var previewExecutorService: ExecutorService? = nullprivate var previewJob: Job? = nulloverride val dataFlow: StateFlow<StudiesData?> get() = _dataFlowprivate val _errorFlow = MutableStateFlow<StudiesPreviewProviderError?>(null)override val errorFlow: StateFlow<StudiesPreviewProviderError?> get() = _errorFlow/*** Starts the background job for processing preview data.* If a previous job exists, it is canceled before starting a new one.** Inside this method, a background job is executed using the [previewExecutorService].* The job collects and combines data from [previewCandlesState], [previewStudyState], and [sessionsFlow]* using the [combine] operator. It then processes the combined data to create a preview version of DX studies.* Finally, it emits the preview studies data to the UI through [_dataFlow].** For details, please, check [DxStudiesDataProviderImplementation.connect]*/fun connect() {if (previewJob != null) {previewJob?.cancel()previewJob = null}if (previewExecutorService == null || previewExecutorService?.isShutdown == true) {previewExecutorService = Executors.newFixedThreadPool(1)previewExecutorService?.execute {runBlocking {previewJob = launch(Dispatchers.IO) {previewCandlesState.combine(previewStudyState,transform = { candles, study -> Pair(candles, study) }).combine(sessionsFlow,transform = { pair, list -> Pair(pair, list) }).collect { pair ->val candles = pair.first.firstval studiesSetting = pair.first.secondval sessions = pair.secondval dxStudies = DxStudies(candles.candlesData.size,candles.candlesData.map { it.toStudiesCandle() }.toTypedArray())try {if (candles.aggregation.isDayOrMore()) {dxStudies.setTradingSessions(candles.candlesData.zipWithNext().map { (candle, nextCandle) ->object : TradingSessionData {override val from: Double =candle.timestamp.toDouble()override val high: Double? = nulloverride val low: Double? = nulloverride val to: Double =nextCandle.timestamp.toDouble()}}.toTypedArray())} else {dxStudies.setTradingSessions(sessions.map { session ->object : TradingSessionData {override val from: Double = session.fromoverride val to: Double = session.tooverride val high: Double? = session.highoverride val low: Double? = session.low}}.toTypedArray())}studiesSetting?.let {val params = getParams(it).toTypedArray()_dataFlow.emit(StudiesData(it.uuid,dxStudies.createStudy(it.id, params).calculateAll()))}} catch (e: Exception) {_errorFlow.tryEmit(StudiesPreviewProviderError.UnknownError("Failed to process studies data: $e.message", e))}}}}}} else {Log.w(TAG, "ExecutorService is already running.")}}/*** Stops the background job for processing preview data and shuts down the executor service.*/fun disconnect() {previewJob?.cancel()previewJob = nullpreviewExecutorService?.shutdown()previewExecutorService = null}/*** Sets the preview DX chart candles for processing.** @param candles The preview DX chart candles.*/override fun setPreviewCandles(candles: DxChartsCandles) {previewCandlesState.tryEmit(candles)}/*** Sets the preview studies setting for processing.** @param studySetting The preview studies setting.*/override fun setPreviewStudySetting(studySetting: StudiesSetting) {previewStudyState.tryEmit(studySetting)}/*** Converts studies configuration parameters to a list of [StudyParam].** @param studiesConfig The studies configuration.* @return List of [StudyParam] representing the configuration parameters.*/private fun getParams(studiesConfig: StudiesSetting): List<StudyParam> {return studiesConfig.parameters.map { it.toStudyParam() }}/*** Retrieves the list of preview trading sessions for processing.** @param sessions The list of preview trading sessions.*/override fun updateTradingSessions(sessions: List<TradingSession>) {sessionsFlow.tryEmit(sessions)}companion object {private const val TAG = "DxStudiesPreviewDataProvider"}}/*** Sealed class representing different types of errors that might occur in the DxStudiesDataProviderImplementation.*/sealed class StudiesPreviewProviderError(override val message: String, override val error: Throwable?) : ProviderError {class UnknownError(override val message: String,override val error: Throwable? = null) : StudiesPreviewProviderError(message, error)}